package com.wsoft.utils.job;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.wsoft.core.context.AuthLoginModeContextHolder;
import com.wsoft.entity.TsJobEntity;
import com.wsoft.entity.TsJobLogEntity;
import com.wsoft.handler.JobHandler;
import com.wsoft.utils.JobUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * job 执行器
 * @Author z001
 * @Date 2024/10/23 13:57
 */
@Slf4j
public class JobExecutor implements Runnable{

    private final TsJobEntity jobEntity;

    private final JobHandler jobInterface;

    private final JobRepository jobRepository;

    public JobExecutor( TsJobEntity jobEntity, JobHandler jobInterface, JobRepository jobRepository) {
        this.jobEntity = jobEntity;
        this.jobInterface = jobInterface;
        this.jobRepository = jobRepository;

    }

    @Override
    public void run() {
        Long jobId = jobEntity.getId();
        try {
            // 查询上次执行时间 校验执行间隔
            TsJobEntity dbJobEntity = jobRepository.getJobManager().getById(jobId);

            if (null == dbJobEntity) {
                return;
            }
            LocalDateTime lastExecuteTime = dbJobEntity.getLastExecuteTime();
            if (null != lastExecuteTime) {
                LocalDateTime nextTime = JobUtil.queryNextTimeFromLast( jobEntity.getCron(), lastExecuteTime, 1).get(0);
                if (LocalDateTime.now().isBefore(nextTime)) {
                    return;
                }
            }
            // 执行任务
            AuthLoginModeContextHolder.need();
            TsJobLogEntity logEntity = this.execute();
        } catch (Throwable t) {
            log.error("==== Job ==== execute err:", t);
        }finally {
        }
    }


    /**
     * 执行任务
     *
     * @param executorName
     */
    public TsJobLogEntity execute() {

        // 保存执行记录
        LocalDateTime startTime = LocalDateTime.now();
        Long logId = this.saveLogBeforeExecute(jobEntity, startTime);

        // 执行计时
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 执行任务
        Integer result = 1;
        String executeResult;
        try {
            executeResult = jobInterface.run(jobEntity.getParams());
            stopWatch.stop();
        } catch (Throwable t) {
            stopWatch.stop();
            result = 0;
            // ps:异常信息不大于数据库字段长度限制
            executeResult = ExceptionUtil.stacktraceToString(t, 1800);
            log.error("==== wsoft-ass ==== execute err:", t);
        }

        // 更新执行记录
        TsJobLogEntity logEntity = new TsJobLogEntity();
        logEntity.setId(logId);
        logEntity.setResult(result);
        long totalTimeMillis = stopWatch.getTotalTimeMillis();
        logEntity.setExecuteTimeMillis(totalTimeMillis);
        logEntity.setEndTime(startTime.plus(totalTimeMillis, ChronoUnit.MILLIS));
        logEntity.setException(executeResult);
        jobRepository.getJobLogManager().updateById(logEntity);
        return logEntity;
    }


    /**
     * 执行前 保存执行记录
     *
     * @param jobEntity
     * @param executorName
     * @param executeTime
     * @return 返回执行记录id
     */
    private Long saveLogBeforeExecute(TsJobEntity jobEntity,
                                      LocalDateTime executeTime) {

        Long jobId = jobEntity.getId();
        // 保存执行记录
        TsJobLogEntity logEntity = new TsJobLogEntity();
        logEntity.setJobId(jobId);
        logEntity.setName(jobEntity.getName());
        logEntity.setCode(jobEntity.getCode());
        logEntity.setParams(jobEntity.getParams());
        logEntity.setCron(jobEntity.getCron());
        logEntity.setClassPath(jobEntity.getClassPath());
        logEntity.setDescription(jobEntity.getDescription());
        logEntity.setResult(1);
        // 执行开始时间
        logEntity.setStartTime(executeTime);
        logEntity.setEndTime(executeTime);
        logEntity.setExecuteTimeMillis(0L);

        // 更新最后执行时间
        TsJobEntity updateJobEntity = new TsJobEntity();
        updateJobEntity.setId(jobId);
        updateJobEntity.setLastExecuteTime(executeTime);

        jobRepository.saveLog(logEntity, updateJobEntity);
        return logEntity.getId();
    }

    /**
     * 查询 当前任务信息
     *
     * @return
     */
    public TsJobEntity getJob() {
        return jobEntity;
    }

}
